home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 1 / QRZ Ham Radio Callsign Database - December 1993.iso / ucsd / drivers.arc / WD8003E.ASM < prev    next >
Encoding:
Assembly Source File  |  1988-10-20  |  24.2 KB  |  728 lines

  1. version    equ    3
  2.  
  3.     include    defs.asm    ;SEE ENCLOSED COPYRIGHT MESSAGE
  4.  
  5. ;/* PC/FTP Packet Driver source, conforming to version 1.05 of the spec
  6. ;*  Robert C Clements, K1BC,  August 19, 1988
  7. ;*  Portions (C) Copyright 1988 Robert C Clements
  8. ;*
  9. ;*  Permission is granted to any individual or institution to use, copy,
  10. ;*  modify, or redistribute this software and its documentation provided
  11. ;*  this notice and the copyright notices are retained.  This software may
  12. ;*  not be distributed for profit, either in original form or in derivative
  13. ;*  works.  Robert C Clements makes no representations about the suitability
  14. ;*  of this software for any purpose.  ROBERT C CLEMENTS GIVES NO WARRANTY,
  15. ;*  EITHER EXPRESS OR IMPLIED, FOR THE PROGRAM AND/OR DOCUMENTATION
  16. ;*  PROVIDED, INCLUDING, WITHOUT LIMITATION, WARRANTY OF MERCHANTABILITY
  17. ;*  AND WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE.
  18. ;*
  19. ;*  Structure patterned on work of Russell Nelson and Phil Karn.
  20. ;*/
  21.  
  22. code    segment    byte public
  23.     assume    cs:code, ds:code
  24.  
  25. HT    equ    09h
  26. CR    equ    0dh
  27. LF    equ    0ah
  28.  
  29. ;
  30. ;  Packet Driver Error numbers
  31. BAD_HANDLE    equ    1        ;invalid handle number
  32. NO_CLASS    equ    2        ;no interfaces of specified class found
  33. NO_TYPE        equ    3        ;no interfaces of specified type found
  34. NO_NUMBER    equ    4        ;no interfaces of specified number found
  35. BAD_TYPE    equ    5        ;bad packet type specified
  36. NO_MULTICAST    equ    6        ;this interface does not support
  37. CANT_TERMINATE    equ    7        ;this packet driver cannot terminate
  38. BAD_MODE    equ    8        ;an invalid receiver mode was specified
  39. NO_SPACE    equ    9        ;operation failed because of insufficient
  40. TYPE_INUSE    equ    10        ;the type had previously been accessed,
  41. BAD_COMMAND    equ    11        ;the command was out of range, or not
  42. CANT_SEND    equ    12        ;the packet couldn't be sent (usually
  43.  
  44. ; Stuff specific to the Western Digital WD003E Ethernet controller board
  45. ; C version by Bob Clements, K1BC, May 1988 for the KA9Q TCP/IP package
  46. ; Symbol prefix "EW" is for Ethernet, Western-digital card
  47.  
  48. ; The EW registers - First, the board registers */
  49.  
  50. EW_CMD        equ    000h    ; Board's command register
  51. EW_SAPROM    equ    008h    ; Window on station addr prom
  52.  
  53. ; The EW registers - Next, the DS8390 chip registers */
  54. ; There are two (really 3) pages of registers in the chip. You select
  55. ; which page you want, then address them at offsets 10-1F from base.
  56. ; The chip command register (EW_CCMD) appears in both pages.
  57.  
  58. EW_CCMD        equ    010h    ; Chip's command register
  59.  
  60. ; Page 0
  61.  
  62. EW0_STARTPG    equ    011h    ; Starting page of ring bfr
  63. EW0_STOPPG    equ    012h    ; Ending page +1 of ring bfr
  64. EW0_BOUNDARY    equ    013h    ; Boundary page of ring bfr
  65. EW0_TSR        equ    014h    ; Transmit status reg
  66. EW0_TPSR    equ    014h    ; Transmit starting page
  67. EW0_TCNTLO    equ    015h    ; Low  byte of tx byte count
  68. EW0_TCNTHI    equ    016h    ; High byte of tx byte count
  69. EW0_ISR        equ    017h    ; Interrupt status reg
  70. EW0_RCNTLO    equ    01ah    ; Remote byte count reg
  71. EW0_RCNTHI    equ    01bh    ; Remote byte count reg
  72. EW0_RXCR    equ    01ch    ; RX control reg
  73. EW0_TXCR    equ    01dh    ; TX control reg
  74. EW0_COUNTER0    equ    01dh    ; Rcv alignment error counter
  75. EW0_DCFG    equ    01eh    ; Data configuration reg
  76. EW0_COUNTER1    equ    01eh    ; Rcv CRC error counter
  77. EW0_IMR        equ    01fh    ; Interrupt mask reg
  78. EW0_COUNTER2    equ    01fh    ; Rcv missed frame error counter
  79.  
  80. ; Page 1
  81.  
  82. EW1_PHYS    equ    011h    ; This board's physical enet addr
  83. EW1_CURPAG    equ    017h    ; Current memory page
  84. EW1_MULT    equ    018h    ; Desired multicast addr
  85.  
  86.  
  87. ; Board commands in EW_CMD
  88. EW_RESET    equ    080h    ; Reset the board
  89. EW_MEMEN    equ    040h    ; Enable the shared memory
  90. EW_MEM_MASK    equ    03fh    ; B18-B13 of address of the shared memory
  91.  
  92. ; Chip commands in EW_CCMD
  93. EWC_STOP    equ    001h    ; Stop the chip
  94. EWC_START    equ    002h    ; Start the chip
  95. EWC_TRANS    equ    004h    ; Transmit a frame
  96. EWC_NODMA    equ    020h    ; No remote DMA used on this card
  97. EWC_PAGE0    equ    000h    ; Select page 0 of chip registers
  98. EWC_PAGE1    equ    040h    ; Select page 1 of chip registers
  99.  
  100. ; Commands for RX control reg
  101. EWRXCR_MON    equ    020h    ; Monitor mode
  102. EWRXCR_BCST    equ    004h    ; Accept broadcasts
  103.  
  104. ; Commands for TX control reg
  105. EWTXCR_LOOP    equ    002h    ; Set loopback mode
  106.  
  107. ; Bits in EW0_DCFG - Data config register
  108. EWDCFG_BM8    equ    048h    ; Set burst mode, 8 deep FIFO
  109.  
  110. ; Bits in EW0_ISR - Interrupt status register
  111. EWISR_RX    equ    001h    ; Receiver, no error
  112. EWISR_TX    equ    002h    ; Transmitter, no error
  113. EWISR_RX_ERR    equ    004h    ; Receiver, with error
  114. EWISR_TX_ERR    equ    008h    ;    Transmitter, with error
  115. EWISR_OVER    equ    010h    ; Receiver overwrote the ring
  116. EWISR_COUNTERS    equ    020h    ; Counters need emptying
  117. EWISR_RESET    equ    080h    ; Reset completed
  118. EWISR_ALL    equ    03fh    ; Interrupts we will enable
  119.  
  120. ; Bits in received packet status byte and EW0_RSR
  121. EWPS_RXOK    equ    001h    ; Received a good packet
  122.  
  123. ; Bits in TX status reg
  124.  
  125. EWTSR_COLL    equ    004h    ; Collided at least once
  126. EWTSR_COLL16    equ    008h    ; Collided 16 times and was dropped
  127. EWTSR_FU    equ    020h    ; TX FIFO Underrun
  128.  
  129. ; Shared memory management parameters
  130.  
  131. SM_TSTART_PG    equ    0    ; First page of TX buffer
  132. SM_RSTART_PG    equ    6    ; Starting page of ring
  133. SM_RSTOP_PG    equ    32    ; Last page +1 of ring
  134. SM_BASE        equ    0C400h    ; Default para where shared memory starts
  135.                 ; Real value set at attach time.
  136.  
  137. ; Description of header of each packet in receive area of shared memory
  138.  
  139. EW_RBUF_STAT    equ    0    ; Received frame status
  140. EW_RBUF_NXT_PG    equ    1    ; Page after this frame
  141. EW_RBUF_SIZE_LO    equ    2    ; Length of this frame
  142. EW_RBUF_SIZE_HI    equ    3    ; Length of this frame
  143. EW_RBUF_NHDR    equ    4    ; Length of above header area
  144.  
  145. ; End of WD8003E parameter definitions
  146.  
  147. ; The following three values may be overridden from the command line.
  148. ; If they are omitted from the command line, these defaults are used.
  149.  
  150.     public    int_no, io_addr, mem_base
  151. int_no        db    2,0,0,0        ; Interrupt level
  152. io_addr        dw    0280h,0        ; I/O address for card (jumpers)
  153. mem_base    dw    0c400h,0    ; Shared memory addr (software)
  154.  
  155.     public    driver_class, driver_type, driver_name
  156. driver_class    db    1        ;from the packet spec
  157. driver_type    db    14        ;from the packet spec
  158. driver_name    db    'WD8003E',0    ;name of the driver.
  159.  
  160.  
  161. ; send_pkt: - The Transmit Frame routine
  162.  
  163.     public    send_pkt
  164. send_pkt:
  165. ;enter with ds:si -> packet, cx = packet length.
  166. ;exit with nc if ok, or else cy if error, dh set to error number.
  167.     assume    ds:nothing
  168.     loadport        ; Point at chip command register
  169.     setport EW_CCMD        ; ..
  170. tx_wait:
  171.     mov bx,    8000h        ; Avoid infinite loop
  172.     in al,    dx        ; Get chip command state
  173.     test al,EWC_TRANS    ; Is transmitter still running?
  174.     jz    tx_idle        ; Go if free
  175.     dec    bx        ; Count the timeout
  176.     jnz    tx_wait        ; Fall thru if TX is stuck
  177.                 ; Should count these error timeouts
  178.                 ; Maybe need to add recovery logic here
  179. tx_idle:
  180.     mov ax,    mem_base    ; Point at shared memory for copying bytes
  181.     mov es,    ax        ; ..
  182.  
  183.     cmp cx,    RUNT        ; Is the frame long enough?
  184.     jnb    tx_oklen    ; Go if OK
  185.     mov cx,    RUNT        ; Stretch frame to minimum allowed
  186. tx_oklen:
  187.     push    cx        ; Hold count for later
  188.                 ; Now compute destination of move in es:di
  189.     mov ax,    mem_base    ; Compute base of transmit buffer
  190. ;    add ax,    SM_TSTART_PG*16    ; The right page in mem (currently zero)
  191.     mov es,    ax        ; Paragraph of the TX buffer
  192.     xor di,    di        ; Fill starting at beginning of paragraph
  193.     cld            ; Move forward
  194.     test si,1        ; Does source start on odd byte?
  195.     jz    obufeven    ; Go if not
  196.     movsb            ; Yes, move the first byte
  197.     dec    cx        ; Count that byte
  198. obufeven:
  199.     mov    dx,cx        ; save for later test
  200.                 ; Do the bulk of the buffer, a word at a time
  201.     shr cx,    1        ; convert to word count
  202.     jcxz    onobuf        ; Stop if count now zero (can't be, defensive)
  203.     rep    movsw        ; Move the bulk as words
  204. onobuf:    mov cx,    dx        ; now check for odd trailing byte
  205.     test cx,1
  206.     jz    ocnteven    ; Go if none
  207.     movsb            ; Move leftover last byte
  208. ocnteven:
  209.     pop    cx        ; Get back count to give to board
  210.     loadport        ; Base of I/O regs
  211.     setport    EW0_TCNTLO    ; Low byte of TX count
  212.     mov al,    cl        ; Get the count
  213.     out dx,    al        ; Tell card the count
  214.     setport    EW0_TCNTHI    ; High byte of TX count
  215.     mov al,    ch        ; Get the count
  216.     out dx,    al        ; Tell card the count
  217.     setport    EW0_TPSR    ; Transmit Page Start Register
  218.     mov al,    SM_TSTART_PG
  219.     out dx,    al        ; Start the transmitter
  220.     setport    EW_CCMD        ; Chip command reg
  221.     mov al,    EWC_TRANS+EWC_NODMA
  222.     out dx,    al        ; Start the transmitter
  223.  
  224.     ret            ; End of transmit-start routine
  225.  
  226.  
  227.     public    get_address
  228. get_address:
  229. ;get the address of the interface.
  230. ;enter with es:di -> place to get the address, cx = size of address buffer.
  231. ;exit with nc, cx = actual size of address, or cy if buffer not big enough.
  232.     assume ds:code
  233.     cmp cx,    EADDR_LEN    ; Caller wants a reasonable length?
  234.     jb    get_addr_x    ; No, fail.
  235.     mov cx,    EADDR_LEN    ; Yes. Set count for loop
  236.     loadport        ; Base of device
  237.     setport    EW_SAPROM    ; Where the address prom is
  238.     cld            ; Make sure string mode is right
  239. get_addr_loop:
  240.     in al,    dx        ; Get a byte of address
  241.     stosb            ; Feed it to caller
  242.     inc    dx        ; Next byte at next I/O port
  243.     loop    get_addr_loop    ; Loop over six bytes
  244.     mov cx,    EADDR_LEN    ; Tell caller how many bytes we fed him
  245.     clc            ; Carry off says success
  246.     ret
  247. get_addr_x:
  248.     stc            ; Tell caller our addr is too big for him
  249.     ret
  250.  
  251.  
  252.     public    reset_interface
  253. reset_interface:
  254.     assume ds:code
  255.     loadport        ; Base of I/O regs
  256.     setport    EW_CCMD        ; Chip command reg
  257.     mov al,    EWC_STOP+EWC_NODMA
  258.     out dx,    al        ; Stop the DS8390
  259.     setport    EW0_ISR        ; Interrupt status reg
  260.     mov al,    0ffh        ; Clear all pending interrupts
  261.     out dx,    al        ; ..
  262.     setport    EW0_IMR        ; Interrupt mask reg
  263.     xor al,    al        ; Turn off all enables
  264.     out dx,    al        ; ..
  265.     ret
  266.  
  267.  
  268. ;called when we want to determine what to do with a received packet.
  269. ;enter with cx = packet length, es:di -> packet type.
  270. ;It returns with es:di = 0 if don't want this type or if no buffer available.
  271.     extrn    recv_find: near
  272.  
  273. ;called after we have copied the packet into the buffer.
  274. ;enter with ds:si ->the packet, cx = length of the packet.
  275.     extrn    recv_copy: near
  276.  
  277.     extrn    count_in_err: near
  278.     extrn    count_out_err: near
  279.  
  280.     public    recv
  281. recv:
  282. ;called from the recv isr.  All registers have been saved, and ds=cs.
  283. ;Actually, not just receive, but all interrupts come here.
  284. ;Upon exit, the interrupt will be acknowledged.
  285.  
  286.     assume    ds:code
  287. check_isr:            ; Was there an interrupt from this card?
  288.     loadport        ; Point at interrupt status register
  289.     setport    EW0_ISR        ; ..
  290.     in al,    dx        ; Get pending interrupts
  291.     and al,    EWISR_ALL    ; Any?
  292.     jnz    isr_test_overrun
  293.     jmp    interrupt_done    ; Go if none
  294. ; First, a messy procedure for handling the case where the rcvr
  295. ; over-runs its ring buffer.  This is spec'ed by National for the chip.
  296. isr_test_overrun: 
  297.     test al,EWISR_OVER    ; Was there an overrun?
  298.     jnz    recv_overrun    ; Go if so.
  299.     jmp    recv_no_overrun    ; Go if not.
  300. recv_overrun:
  301.     setport    EW_CCMD        ; Stop the card
  302.     mov al,    EWC_STOP+EWC_NODMA
  303.     out dx,    al        ; Write "stop" to command register
  304.  
  305. ; Remove one frame from the ring
  306.     setport    EW0_BOUNDARY    ; Find end of this frame
  307.     in al,    dx        ; Get memory page number
  308.     inc    al        ; Page plus 1
  309.     cmp al,    SM_RSTOP_PG    ; Wrapped around ring?
  310.     jnz    rcv_ovr_nwrap    ; Go if not
  311.     mov al,    SM_RSTART_PG    ; Yes, wrap the page pointer
  312. rcv_ovr_nwrap:
  313.     xor ah,    ah        ; Convert page to segment
  314.     mov cl,    4
  315.     mov bl,    al        ; Page number as arg to rcv_frm
  316.     shl ax,    cl        ; ..
  317.     add ax,    mem_base    ; Page in this memory
  318.     mov es,    ax        ; Segment pointer to the frame header
  319.     push    es        ; Hold this frame pointer for later
  320.     mov al,    es:[EW_RBUF_STAT]    ; Get the buffer status byte
  321.     test al,EWPS_RXOK    ; Is this frame any good?
  322.     jz    rcv_ovr_ng    ; Skip if not
  323.      call    rcv_frm        ; Yes, go accept it
  324. rcv_ovr_ng:
  325.     pop    es        ; Back to start of this frame
  326.     mov al,    es:[EW_RBUF_NXT_PG]    ; Get pointer to next frame
  327.     dec    al        ; Back up one page
  328.     cmp al,    SM_RSTART_PG    ; Did it wrap?
  329.     jge    rcv_ovr_nwr2
  330.     mov al,    SM_RSTOP_PG-1    ; Yes, back to end of ring
  331. rcv_ovr_nwr2:
  332.     loadport        ; Point at boundary reg
  333.     setport    EW0_BOUNDARY    ; ..
  334.     out dx,    al        ; Set the boundary
  335.     setport    EW0_RCNTLO    ; Point at byte count regs
  336.     xor al,    al        ; Clear them
  337.     out dx,    al        ; ..
  338.     setport    EW0_RCNTHI
  339.     out dx,    al
  340.     setport    EW0_ISR        ; Point at status reg
  341.     mov cx,    8000h        ; Timeout counter
  342. rcv_ovr_rst_loop:
  343.     in al,    dx        ; Is it finished resetting?
  344.     test al,EWISR_RESET    ; ..
  345.     jnz    rcv_ovr_rst    ; Go if so
  346.     dec    cx        ; Loop til reset, or til timeout
  347.     jnz    rcv_ovr_rst_loop
  348. rcv_ovr_rst:
  349.     loadport        ; Point at Transmit control reg
  350.      setport    EW0_TXCR    ; ..
  351.     mov al,    EWTXCR_LOOP    ; Put transmitter in loopback mode
  352.     out dx,    al        ; ..
  353.     setport    EW_CCMD        ; Point at Chip command reg
  354.     mov al,    EWC_START+EWC_NODMA
  355.     out dx,    al        ; Start the chip running again
  356.     setport    EW0_TXCR    ; Back to TX control reg
  357.     xor al,    al        ; Clear the loopback bit
  358.     out dx,    al        ; ..
  359.     setport    EW0_ISR        ; Point at Interrupt status register
  360.     mov al,    EWISR_OVER    ; Clear the overrun interrupt bit
  361.     out dx,    al        ; ..
  362.     call    count_in_err    ; Count the anomaly
  363.      jmp    check_isr    ; Done with the overrun case
  364.  
  365. recv_no_overrun:
  366. ; Handle receive flags, normal and with error (but not overrun).
  367.     test al,EWISR_RX+EWISR_RX_ERR    ; Frame received without overrun?
  368.     jnz    recv_frame    ; Go if so.
  369.     jmp    recv_no_frame    ; Go if not.
  370. recv_frame:
  371.     loadport        ; Point at Chip's Command Reg
  372.      setport    EW_CCMD        ; ..
  373.     mov al,    EWC_NODMA+EWC_PAGE1
  374.     out dx,    al        ; Switch to page 1 registers
  375.     setport    EW1_CURPAG    ;Get current page of rcv ring
  376.     in al,    dx        ; ..
  377.     mov ah,    al        ; Hold current page in AH
  378.      setport    EW_CCMD        ; Back to page zero registers
  379.     mov al,    EWC_NODMA+EWC_PAGE0
  380.     out dx,    al        ; Switch back to page 0 registers
  381.     setport    EW0_BOUNDARY    ;Get boundary page
  382.     in al,    dx        ; ..
  383.     inc    al        ; Step boundary from last used page
  384.     cmp al,    SM_RSTOP_PG    ; Wrap if needed
  385.     jne    rx_nwrap3    ; Go if not
  386.     mov al,    SM_RSTART_PG    ; Wrap to first RX page
  387. rx_nwrap3:
  388.     cmp al,    ah        ; Read all the frames?
  389.     je    recv_frame_break    ; Finished them all
  390.     mov bl,    al        ; Page number as arg to rcv_frm
  391.     xor ah,    ah        ; Make segment pointer to this frame
  392.     mov cl,    4        ; 16 * pages = paragraphs
  393.     shl ax,    cl        ; ..
  394.     add ax,    mem_base    ; That far into shared memory
  395.     mov es,    ax        ; Segment part of pointer
  396.     push    es        ; Hold on to this pointer for later
  397.     mov al,    es:[EW_RBUF_STAT]    ; Get the buffer status byte
  398.     test al,EWPS_RXOK    ; Good frame?
  399.     jz    recv_no_rcv
  400.     call    rcv_frm        ; Yes, go accept it
  401. recv_no_rcv:
  402.     pop    es        ; Back to base of frame
  403.     mov al,    es:[EW_RBUF_NXT_PG]    ; Start of next frame
  404.     dec    al        ; Make previous page for new boundary
  405.     cmp al,    SM_RSTART_PG    ; Wrap around the bottom?
  406.     jge    rcv_nwrap4
  407.     mov al,    SM_RSTOP_PG-1    ; Yes
  408. rcv_nwrap4:
  409.     loadport        ; Point at the Boundary Reg again
  410.      setport    EW0_BOUNDARY    ; ..
  411.     out dx,    al        ; Set new boundary
  412.     jmp    recv_frame    ; See if any more frames
  413.  
  414. recv_frame_break:
  415.     loadport        ; Point at Interrupt Status Reg
  416.      setport    EW0_ISR        ; ..
  417.     mov al,    EWISR_RX+EWISR_RX_ERR+EWISR_OVER
  418.     out dx,    al        ; Clear those requests
  419.     jmp    check_isr    ; See if any other interrupts pending
  420.  
  421. recv_no_frame:                ; Handle transmit flags.
  422.     test al,EWISR_TX+EWISR_TX_ERR    ; Frame transmitted?
  423.     jnz    isr_tx        ; Go if so.
  424.     jmp    isr_no_tx    ; Go if not.
  425. isr_tx:
  426.     mov ah,    al        ; Hold interrupt status bits
  427.     loadport        ; Point at Transmit Status Reg
  428.      setport    EW0_TSR        ; ..
  429.     in al,    dx        ; ..
  430.     test ah,EWISR_TX    ; Non-error TX?
  431.     jz    isr_tx_err    ; No, do TX error completion
  432.     test al,EWTSR_COLL16    ; Jammed for 16 transmit tries?
  433.     jz    isr_tx_njam    ; Go if not
  434.     call    count_out_err    ; Yes, count those
  435. isr_tx_njam:
  436.     setport    EW0_ISR        ; Clear the TX complete flag
  437.     mov al,    EWISR_TX    ; ..
  438.     out dx,    al        ; ..    
  439.     jmp    isr_tx_done
  440. isr_tx_err:
  441.     test al,EWTSR_FU    ; FIFO Underrun?
  442.     jz    isr_txerr_nfu
  443.     call    count_out_err    ; Yes, count those
  444. isr_txerr_nfu:
  445.     loadport        ; Clear the TX error completion flag
  446.     setport    EW0_ISR        ; ..
  447.     mov al,    EWISR_TX_ERR    ; ..
  448.     out dx,    al        ; ..    
  449. isr_tx_done:
  450. ; If TX queue and/or TX shared memory ring buffer were being
  451. ; used, logic to step through them would go here.  However,
  452. ; in this version, we just clear the flags for background to notice.
  453.  
  454.      jmp    check_isr    ; See if any other interrupts on
  455.  
  456. isr_no_tx:
  457. ; Now check to see if any counters are getting full
  458.     test al,EWISR_COUNTERS    ; Interrupt to handle counters?
  459.     jnz    isr_stat    ; Go if so.
  460.     jmp    isr_no_stat    ; Go if not.
  461. isr_stat:
  462. ; We have to read the counters to clear them and to clear the interrupt.
  463. ; The structure of the PC/FTP driver system doesn't give us
  464. ; anything useful to do with the data, though.
  465.     loadport        ; Point at first counter
  466.      setport    EW0_COUNTER0    ; ..
  467.     in al,    dx        ; Read the count, ignore it.
  468.     setport    EW0_COUNTER1
  469.     in al,    dx        ; Read the count, ignore it.
  470.     setport    EW0_COUNTER2
  471.     in al,    dx        ; Read the count, ignore it.
  472.     setport    EW0_ISR        ; Clear the statistics completion flag
  473.     mov al,    EWISR_COUNTERS    ; ..
  474.     out dx,    al        ; ..
  475. isr_no_stat:
  476.      jmp    check_isr    ; Anything else to do?
  477.  
  478. interrupt_done:
  479.     ret
  480.  
  481. ; Do the work of copying out a receive frame.
  482. ; Called with bl/ the page number of the frame header in shared memory/
  483. ; Also, es/ the paragraph number of that page.
  484.  
  485. rcv_frm:
  486. ; Old version checked size, memory space, queue length here. Now done
  487. ; in higher level code.
  488. ; Set cx to length of this frame.
  489.     mov ch,    es:[EW_RBUF_SIZE_HI]    ; Extract size of frame
  490.     mov cl,    es:[EW_RBUF_SIZE_LO]    ; Extract size of frame
  491.     sub cx,    EW_RBUF_NHDR        ; Less the header stuff
  492. ; Set es:di to point to Ethernet type field.  es is already at base of
  493. ; page where this frame starts.  Set di after the header and two addresses.
  494.     mov di,    EW_RBUF_NHDR+EADDR_LEN+EADDR_LEN
  495.     push    bx            ; Save page number in bl
  496.     push    cx            ; Save frame size
  497.     push    es
  498.     mov ax,    cs            ; Set ds = code
  499.     mov ds,    ax
  500.     assume    ds:code
  501.     call    recv_find        ; See if type and size are wanted
  502.     pop    ds            ; RX page pointer in ds now
  503.     assume    ds:nothing
  504.     pop    cx
  505.     pop    bx
  506.     cld            ; Copies below are forward, please
  507.     mov ax,    es        ; Did recv_find give us a null pointer?
  508.     or ax,    di        ; ..
  509.     je    rcv_no_copy    ; If null, don't copy the data    
  510.  
  511.     push    cx        ; We will want the count and pointer
  512.     push    es        ;  to hand to client after copying,
  513.     push    di        ;  so save them at this point
  514.  
  515. ;; if ( (((size + 255 + EW_RBUF_NHDR) >> 8) + pg) > SM_RSTOP_PG){
  516.     mov ax,    cx        ; Length of frame
  517.     add ax,    EW_RBUF_NHDR+255 ; Including the overhead bytes, rounded up
  518.     add ah,    bl        ; Compute page with last byte of data in ah
  519.     cmp ah,    SM_RSTOP_PG    ; Over the top of the ring?
  520.     jg    rcopy_wrap    ; Yes, move in two pieces
  521.     mov si,    EW_RBUF_NHDR    ; One piece, starts here in first page (in ds)
  522.     jmp    rcopy_one_piece    ; Go move it
  523.  
  524. rcopy_wrap:
  525. ;; Copy in two pieces due to buffer wraparound. */
  526. ;; n = ((SM_RSTOP_PG - pg) << 8) - EW_RBUF_NHDR;    /* To top of mem */
  527.     mov ah,    SM_RSTOP_PG    ; Compute length of first part
  528.     sub ah,    bl        ;  as all of the pages up to wrap point
  529.     xor al,    al        ; 16-bit count
  530.     sub ax,    EW_RBUF_NHDR    ; Less the four overhead bytes
  531.     sub cx,    ax        ; Move the rest in second part
  532.     push    cx        ; Save count of second part
  533.     mov cx,    ax        ; Count for first move
  534.     mov si,    EW_RBUF_NHDR    ; ds:si points at first byte to move
  535.     shr cx,    1        ; All above are even numbers, do words.
  536.     rep    movsw        ; Move first part of frame
  537.     mov ax,    mem_base    ; Paragraph of base of shared memory
  538.     mov ds,    ax        ; ..
  539.     mov si,    SM_RSTART_PG*256  ; Offset to start of first receive page
  540.     pop    cx        ; Bytes left to move
  541. rcopy_one_piece:
  542.     push    cx        ; Save count for odd byte check
  543.     shr cx,    1        ; Make word count
  544.     rep    movsw        ; Move the words
  545.     pop    cx        ; A final byte?
  546.     shr cx,    1        ; Low bit to carry
  547.     jnc    rcopy_even    ; Go if no last byte
  548.     movsb            ; Yes, move it
  549. rcopy_even:
  550.     pop    si        ; Recover pointer to destination
  551.     pop    ds        ; Tell client it's his source
  552.     pop    cx        ; And it's this long
  553.     assume    ds:nothing
  554.     call    recv_copy    ; Give it to him
  555. rcv_no_copy:
  556.     push    cs        ; Put ds back in code space
  557.     pop    ds        ; ..
  558.     assume    ds:code
  559.     ret            ; That's it for rcv_frm
  560.  
  561.  
  562. ;any code after this will not be kept after initialization.
  563. end_resident    label    byte
  564.  
  565.  
  566.     public    usage_msg
  567. usage_msg    db    "usage: WD8003E <packet_int_no> <int_level> <io_addr> <mem_base>",CR,LF,'$'
  568.  
  569.     public    copyright_msg
  570. copyright_msg    db    "Packet driver for Western Digital WD8003E, version ",'0'+version,CR,LF
  571.         db    "Portions Copyright 1988, Robert C. Clements, K1BC",CR,LF,'$'
  572.  
  573. no_board_msg:
  574.     db    "WD8003E apparently not present at this address.",CR,LF,'$'
  575. int_no_name    db    "Interrupt number ",'$'
  576. io_addr_name    db    "I/O port ",'$'
  577. mem_base_name    db    "Memory address ",'$'
  578.  
  579.     extrn    set_recv_isr: near
  580.  
  581. ;enter with si -> argument string, di -> word to store.
  582. ;if there is no number, don't change the number.
  583.     extrn    get_number: near
  584.  
  585.     public    parse_args
  586. parse_args:
  587.     mov    di,offset int_no
  588.     mov    bx,offset int_no_name
  589.     call    get_number
  590.     mov    di,offset io_addr
  591.     mov    bx,offset io_addr_name
  592.     call    get_number
  593.     mov    di,offset mem_base
  594.     mov    bx,offset mem_base_name
  595.     call    get_number
  596.     ret
  597.  
  598.  
  599. bad_cksum:
  600.     mov    dx,offset no_board_msg
  601.     mov    ah,9
  602.     int    21h
  603.     stc
  604.     ret
  605.  
  606.  
  607.     public    etopen
  608. etopen:                ; Initialize interface
  609.     loadport        ; First, pulse the board reset
  610.     setport    EW_CMD
  611.     mov al,    EW_RESET
  612.     out dx,    al        ; Turn on board reset bit
  613.     xor al,    al
  614.     out dx,    al        ; Turn off board reset bit
  615.     setport    EW_CCMD        ; DS8390 chip's command register
  616.     mov al,    EWC_NODMA+EWC_PAGE0    
  617.     out dx,    al        ; Switch to page zero
  618.     setport    EW0_ISR        ; Clear all interrupt flags
  619.     mov al,    0ffh        ; ..
  620.     out dx,    al        ; ..
  621. ; Copy our Ethernet address from PROM into the DS8390
  622. ; (No provision in driver spec for setting a false address.)
  623.     setport    EW_CCMD        ; Chip command register
  624.     mov al,    EWC_NODMA+EWC_PAGE1
  625.     out dx,    al        ; Switch to page one for writing eaddr
  626.     mov cl,    EADDR_LEN    ; Loop for six bytes
  627.     xor ch,    ch        ; Clear the index of bytes
  628.     xor bx,    bx        ; Clear the addr ROM checksum
  629. cpy_adr_loop:
  630.     loadport        ; Base of registers
  631.     setport    EW_SAPROM    ; Prom address
  632.     add dl,    ch        ; Plus which byte this is
  633.     in al,    dx        ; Get a byte of address
  634.     add    bl,al        ; Compute the checksum
  635.     add dl,    EW1_PHYS-EW_SAPROM ; Point at reg in chip
  636.     out dx,    al        ; Copy that byte
  637.     inc    ch        ; Step the index
  638.     dec    cl        ; Count bytes
  639.     jnz    cpy_adr_loop    ; Loop for six
  640.     loadport        ; Get last two bytes into cksum
  641.     setport    EW_SAPROM+EADDR_LEN
  642.     in al,    dx        ; Get seventh byte
  643.     add bl,    al        ; Add it in
  644.     inc    dx        ; Step to eighth byte
  645.     in al,    dx        ; Get last byte
  646.     add bl,    al        ; Final checksum
  647.     cmp bl, 0ffh        ; Correct?
  648.     jnz    bad_cksum    ; No, board is not happy
  649. ; Clear the multicast filter enables, we don't want any of them.
  650.     mov cl,    8        ; Eight bytes of multicast filter
  651.     xor al,    al        ; Zeros for filter
  652.     loadport        ; Base of multicast filter locations
  653.     setport    EW1_MULT    ; ..
  654. clr_mcast_l:
  655.     out dx,    al        ; Clear a byte
  656.     inc    dl        ; Step to next one
  657.     dec    cl        ; Count 8 filter locs
  658.     jnz    clr_mcast_l    ; ..    
  659.     loadport        ; Base of I/O regs
  660.     setport    EW_CCMD        ; Chip command register
  661.     mov al,    EWC_NODMA+EWC_PAGE0
  662.     out dx,    al        ; Back to page zero
  663.     setport    EW0_DCFG    ; Configure the fifo organization
  664.     mov al,    EWDCFG_BM8    ; Fifo threshold = 8 bytes
  665.     out dx,    al
  666.     setport    EW0_RCNTLO    ; Clear the byte count registers
  667.     xor al,    al        ; ..
  668.     out dx,    al
  669.     setport    EW0_RCNTHI
  670.     out dx,    al        ; Clear high byte, too
  671.     setport    EW0_RXCR    ; Set receiver to monitor mode
  672.     mov al,    EWRXCR_MON
  673.     out dx,    al
  674.     setport    EW0_TXCR    ; Set transmitter mode to normal
  675.     xor al,    al
  676.     out dx,    al
  677. ; Turn on the shared memory block
  678.     setport    EW_CMD        ; Point at board command register
  679.     mov ax,    mem_base    ; Find where shared memory will be mapped
  680.     mov al,    ah        ; Shift to right location
  681.     sar al,    1        ;  in the map control word
  682.     and al,    EW_MEM_MASK    ; Just these bits
  683.     or al,    EW_MEMEN    ; Command to turn on map
  684.     out dx,    al        ; Create that memory
  685. ; Set up control of shared memory, buffer ring, etc.
  686.     setport    EW0_STARTPG    ; Set receiver's first buffer page
  687.     mov al,    SM_RSTART_PG
  688.     out dx,    al
  689.     setport    EW0_STOPPG    ;  and receiver's last buffer page + 1
  690.     mov al,    SM_RSTOP_PG
  691.     out dx,    al
  692.     setport    EW0_BOUNDARY    ; Set initial "last page we have emptied"
  693.     mov al,    SM_RSTART_PG
  694.     out dx,    al
  695.     setport    EW_CCMD        ; Switch to page one registers
  696.     mov al,    EWC_NODMA+EWC_PAGE1
  697.     out dx,    al
  698.     setport    EW1_CURPAG    ; Set current shared page for RX to work on
  699.     mov al,    SM_RSTART_PG+1
  700.     out dx,    al
  701.     setport    EW_CCMD        ; Switch back to page zero registers
  702.     mov al,    EWC_NODMA+EWC_PAGE0
  703.     out dx,    al
  704.     setport    EW0_IMR        ; Clear all interrupt enable flags
  705.     xor al,    al
  706.     out dx,    al
  707.     setport    EW0_ISR        ; Clear all interrupt assertion flags
  708.     mov al,    0ffh        ; again for safety before making the
  709.     out dx,    al        ; interrupt be enabled
  710.     call    set_recv_isr    ; Put ourselves in interrupt chain
  711.     loadport
  712.     setport    EW_CCMD        ; Now start the DS8390
  713.     mov al,    EWC_START+EWC_NODMA
  714.     out dx,    al        ; interrupt be enabled
  715.     setport    EW0_RXCR    ; Tell it to accept broadcasts
  716.     mov al,    EWRXCR_BCST
  717.     out dx,    al
  718.     setport    EW0_IMR        ; Tell card it can cause these interrupts
  719.     mov al,    EWISR_ALL
  720.     out dx,    al
  721.     mov    dx,offset end_resident
  722.     clc
  723.     ret
  724.  
  725. code    ends
  726.  
  727.     end
  728.